package com.hdphone.zljutils.impl;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import com.hdphone.zljutils.ZljUtils;
import com.hdphone.zljutils.constant.ImeiBlackList;
import com.hdphone.zljutils.inter.IRomUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;
import androidx.core.app.ActivityCompat;

/**
 * @author sq
 * @date 2020/10/19
 * @describe
 */
public class RomUtilImpl implements IRomUtil {
    private final String[] ROM_HUAWEI = {"huawei"};
    private final String[] ROM_VIVO = {"vivo"};
    private final String[] ROM_XIAOMI = {"xiaomi"};
    private final String[] ROM_OPPO = {"oppo"};
    private final String[] ROM_REALME = {"realme"};
    private final String[] ROM_LEECO = {"leeco", "letv"};
    private final String[] ROM_360 = {"360", "qiku"};
    private final String[] ROM_ZTE = {"zte"};
    private final String[] ROM_ONEPLUS = {"oneplus"};
    private final String[] ROM_NUBIA = {"nubia"};
    private final String[] ROM_COOLPAD = {"coolpad", "yulong"};
    private final String[] ROM_LG = {"lg", "lge"};
    private final String[] ROM_GOOGLE = {"google"};
    private final String[] ROM_SAMSUNG = {"samsung"};
    private final String[] ROM_MEIZU = {"meizu"};
    private final String[] ROM_LENOVO = {"lenovo"};
    private final String[] ROM_SMARTISAN = {"smartisan"};
    private final String[] ROM_HTC = {"htc"};
    private final String[] ROM_SONY = {"sony"};
    private final String[] ROM_GIONEE = {"gionee", "amigo"};
    private final String[] ROM_MOTOROLA = {"motorola"};
    private final String[] ROM_MEITU = {"meitu"};

    private final String VERSION_PROPERTY_HUAWEI = "ro.build.version.emui";
    private final String VERSION_PROPERTY_VIVO = "ro.vivo.os.build.display.id";
    private final String VERSION_PROPERTY_XIAOMI = "ro.build.version.incremental";
    private final String VERSION_PROPERTY_OPPO = "ro.build.version.opporom";
    private final String VERSION_PROPERTY_LEECO = "ro.letv.release.version";
    private final String VERSION_PROPERTY_360 = "ro.build.uiversion";
    private final String VERSION_PROPERTY_ZTE = "ro.build.MiFavor_version";
    private final String VERSION_PROPERTY_ONEPLUS = "ro.rom.version";
    private final String VERSION_PROPERTY_NUBIA = "ro.build.rom.id";
    private final String UNKNOWN = "unknown";

    private final Map<String, String> mModelMap = new HashMap<>();


    /**
     * 维护小型号映射表
     */
    private void initTinyModel() {
        mModelMap.put("LYA-AL00", "ro.config.marketing_name");
        mModelMap.put("LYA-TL00", "ro.config.marketing_name");
        mModelMap.put("BLA-AL00", "ro.config.marketing_name");
        mModelMap.put("BLA-TL00", "ro.config.marketing_name");
        mModelMap.put("PAFT00", "ro.oppo.market.name");
        mModelMap.put("PAFM00", "ro.oppo.market.name");
        mModelMap.put("V1818A", "ro.vivo.market.name");
        mModelMap.put("V1818T", "ro.vivo.market.name");
        mModelMap.put("V1818CA", "ro.vivo.market.name");
        mModelMap.put("V1818CT", "ro.vivo.market.name");
        mModelMap.put("V1813A", "ro.vivo.market.name");
        mModelMap.put("V1813T", "ro.vivo.market.name");
        mModelMap.put("V1824A", "ro.vivo.market.name");
        mModelMap.put("V1824BA", "ro.vivo.market.name");
        mModelMap.put("V2002A", "ro.vendor.vivo.market.name");
        mModelMap.put("V1732A", "ro.vivo.market.name");
        //[ro.vivo.oem.name]: [PD1728UD_FULL_SC]
        //[ro.vivo.oem.name]: [PD1728UD_CT-FIFA]
        mModelMap.put("vivo X21UD A", "ro.vivo.oem.name");
        mModelMap.put("V1730EA", "ro.vivo.market.name");
        mModelMap.put("NX629J", "persist.sys.devicename");
        mModelMap.put("NX659J", "persist.sys.devicename");
        mModelMap.put("ONEPLUS A6000", "ro.product.name");
        mModelMap.put("RMX2176", "ro.oppo.market.name");
        mModelMap.put("RMX2121", "ro.oppo.market.name");

        mModelMap.put("V1901A", "ro.vivo.market.name");//VIVO
        mModelMap.put("V1941A", "ro.vivo.market.name");//VIVO
        mModelMap.put("LYA-L29", "ro.config.marketing_name");//HUAWEI
        mModelMap.put("SPN-AL00", "ro.config.marketing_name");//HUAWEI NOVA 5z
        mModelMap.put("PCLM50", "ro.oppo.market.name");
        mModelMap.put("WLZ-AN00", "ro.config.marketing_name");
        mModelMap.put("PCRT01", "ro.oppo.market.name");
        mModelMap.put("SM-G9880", "ro.product.name");//samsung s20 ultra 5g
//        mModelMap.put("20190419Q", "");
//        mModelMap.put("SHARK KLE-A0", "");
        mModelMap.put("RMX2117", "ro.oppo.market.name");
        mModelMap.put("RMX1971", "ro.oppo.market.name");
        mModelMap.put("CND-AN00", "ro.config.marketing_name");
        mModelMap.put("LON-AL00", "ro.config.marketing_name");
//        mModelMap.put("ZTE A7000", "");
        mModelMap.put("V1731CA", "ro.vivo.market.name");
        mModelMap.put("V1732T", "ro.vivo.market.name");//VIVO Y81S
        mModelMap.put("RMX2142", "ro.oppo.market.name");//REALME
        mModelMap.put("V2031A", "ro.vendor.vivo.market.name");
        mModelMap.put("SM-G9750", "ro.product.name");//SAMSUNG S10+
        mModelMap.put("NOH-AN00", "ro.config.marketing_name");
        mModelMap.put("NX589J", "ro.config.devicename");
        mModelMap.put("WAS-TL10", "ro.config.marketing_name");//HUAWEI P10
//        mModelMap.put("20190718Q", "");//小辣椒
        mModelMap.put("ANE-AL00", "ro.config.marketing_name");//huawei NOVA 3E
        mModelMap.put("RNE-L22", "ro.config.marketing_name");//HONOR 9I
//        mModelMap.put("SEA-A0", "");//COOLPAD
        mModelMap.put("RMX2200", "ro.oppo.market.name");//REALME Q2I
        mModelMap.put("COR-L29", "ro.config.marketing_name");//HONOR PLAY
        mModelMap.put("PDEM30", "ro.oppo.market.name");//OPPO FIND X2
        mModelMap.put("STF-L09", "ro.config.marketing_name");//HORNOR 9
        mModelMap.put("CHM-CL00", "ro.config.marketing_name");//畅玩4c
        mModelMap.put("SM-G9500", "ro.product.name");//samsung s8
        mModelMap.put("JNY-LX1", "ro.config.marketing_name");
//        mModelMap.put("20190325D", "");
//        mModelMap.put("JEF", "");
        mModelMap.put("V1813BA", "ro.vivo.market.name");//vivo z3
//        mModelMap.put("20190808", "");
//        mModelMap.put("LM-V510N", "");
        mModelMap.put("JSC-AN00", "ro.config.marketing_name");
//        mModelMap.put("20200308", "");
//        mModelMap.put("20200606", "");
        mModelMap.put("OXF", "ro.config.marketing_name");//honor v30 pro
        mModelMap.put("SM-G6100", "ro.product.name");//三星 Galaxy J7 Prime
        mModelMap.put("SM-N9700", "ro.product.name");
//        mModelMap.put("SO-02K", "");//索尼 Xperia XZ1
//        mModelMap.put("GIONEE S11", "");
        mModelMap.put("M5", "ro.product.name");
        mModelMap.put("20200519", "ro.product.name");
    }

    private RomInfo bean = null;

    /**
     * Return whether the rom is made by huawei.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isHuawei() {
        return ROM_HUAWEI[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by vivo.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isVivo() {
        return ROM_VIVO[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by xiaomi.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isXiaomi() {
        return ROM_XIAOMI[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by oppo.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isOppo() {
        return ROM_OPPO[0].equals(getRomInfo().name);
    }

    @Override
    public boolean isRealMe() {
        return ROM_REALME[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by leeco.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isLeeco() {
        return ROM_LEECO[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by 360.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean is360() {
        return ROM_360[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by zte.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isZte() {
        return ROM_ZTE[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by oneplus.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isOneplus() {
        return ROM_ONEPLUS[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by nubia.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isNubia() {
        return ROM_NUBIA[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by coolpad.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isCoolpad() {
        return ROM_COOLPAD[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by lg.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isLg() {
        return ROM_LG[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by google.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isGoogle() {
        return ROM_GOOGLE[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by samsung.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isSamsung() {
        return ROM_SAMSUNG[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by meizu.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isMeizu() {
        return ROM_MEIZU[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by lenovo.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isLenovo() {
        return ROM_LENOVO[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by smartisan.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isSmartisan() {
        return ROM_SMARTISAN[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by htc.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isHtc() {
        return ROM_HTC[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by sony.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isSony() {
        return ROM_SONY[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by gionee.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isGionee() {
        return ROM_GIONEE[0].equals(getRomInfo().name);
    }

    /**
     * Return whether the rom is made by motorola.
     *
     * @return {@code true}: yes<br>{@code false}: no
     */
    @Override
    public boolean isMotorola() {
        return ROM_MOTOROLA[0].equals(getRomInfo().name);
    }

    @Override
    public boolean isHonor() {
        String brand = Build.BRAND;
        if (brand.equalsIgnoreCase("honor")) {
            return true;
        }

        if (brand.equalsIgnoreCase("huawei")) {
            String realBrand = getRealBrand();
            return realBrand.equalsIgnoreCase("honor");
        }

        return false;
    }

    @Override
    public boolean isMeitu() {
        return ROM_MEITU[0].equals(getRomInfo().name);

    }

    @Override
    public boolean isVivoLiftCamera() {
        if (!isVivo()) {
            return false;
        }

        String phoneModel = Build.MODEL.toLowerCase();
        return VivoLiftCameraModelList.mModelList.contains(phoneModel);
    }

    @Override
    public @Nullable
    String getCpuAbi() {
        String cpuabi = null;
        try {
            String os_cpuabi = getSystemPropertyByShell("ro.product.cpu.abi");
            if (os_cpuabi.contains("x86")) {
                cpuabi = "x86";
            } else if (os_cpuabi.contains("armeabi-v7a")) {
                cpuabi = "armeabi-v7a";
            } else if (os_cpuabi.contains("arm64-v8a")) {
                cpuabi = "arm64-v8a";
            }
        } catch (Exception e) {
        }

        return cpuabi;
    }

    @Override
    public boolean isIqoo() {
        if (!isVivo()) {
            return false;
        }
        try {
            String serialName = getSystemPropertyByShell("ro.vivo.product.series");

            if ("iqoo".equalsIgnoreCase(serialName)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    private @NonNull
    String getRealBrand() {
        Class<?> classType = null;
        String buildVersion = null;
        try {
            classType = Class.forName("android.os.SystemProperties");
            Method getMethod = classType.getDeclaredMethod("get", new Class<?>[]{String.class});
            getMethod.setAccessible(true);
            buildVersion = (String) getMethod.invoke(classType, new Object[]{"ro.product.brand"});
        } catch (Exception e) {
            e.printStackTrace();
        }
        return buildVersion == null ? "" : buildVersion;
    }

    /**
     * Return the rom's information.
     *
     * @return the rom's information
     */
    @Override
    public RomInfo getRomInfo() {
        if (bean != null) return bean;
        bean = new RomInfo();
        final String brand = getBrand();
        final String manufacturer = getManufacturer();
        if (isRightRom(brand, manufacturer, ROM_HUAWEI)) {
            bean.name = ROM_HUAWEI[0];
            String version = getRomVersion(VERSION_PROPERTY_HUAWEI);
            String[] temp = version.split("_");
            if (temp.length > 1) {
                bean.version = temp[1];
            } else {
                bean.version = version;
            }
            return bean;
        }
        if (isRightRom(brand, manufacturer, ROM_VIVO)) {
            bean.name = ROM_VIVO[0];
            bean.version = getRomVersion(VERSION_PROPERTY_VIVO);
            return bean;
        }
        if (isRightRom(brand, manufacturer, ROM_XIAOMI)) {
            bean.name = ROM_XIAOMI[0];
            bean.version = getRomVersion(VERSION_PROPERTY_XIAOMI);
            return bean;
        }
        if (isRightRom(brand, manufacturer, ROM_OPPO)) {
            bean.name = ROM_OPPO[0];
            bean.version = getRomVersion(VERSION_PROPERTY_OPPO);
            return bean;
        }
        if (isRightRom(brand, manufacturer, ROM_LEECO)) {
            bean.name = ROM_LEECO[0];
            bean.version = getRomVersion(VERSION_PROPERTY_LEECO);
            return bean;
        }

        if (isRightRom(brand, manufacturer, ROM_360)) {
            bean.name = ROM_360[0];
            bean.version = getRomVersion(VERSION_PROPERTY_360);
            return bean;
        }
        if (isRightRom(brand, manufacturer, ROM_ZTE)) {
            bean.name = ROM_ZTE[0];
            bean.version = getRomVersion(VERSION_PROPERTY_ZTE);
            return bean;
        }
        if (isRightRom(brand, manufacturer, ROM_ONEPLUS)) {
            bean.name = ROM_ONEPLUS[0];
            bean.version = getRomVersion(VERSION_PROPERTY_ONEPLUS);
            return bean;
        }
        if (isRightRom(brand, manufacturer, ROM_NUBIA)) {
            bean.name = ROM_NUBIA[0];
            bean.version = getRomVersion(VERSION_PROPERTY_NUBIA);
            return bean;
        }

        if (isRightRom(brand, manufacturer, ROM_COOLPAD)) {
            bean.name = ROM_COOLPAD[0];
        } else if (isRightRom(brand, manufacturer, ROM_LG)) {
            bean.name = ROM_LG[0];
        } else if (isRightRom(brand, manufacturer, ROM_GOOGLE)) {
            bean.name = ROM_GOOGLE[0];
        } else if (isRightRom(brand, manufacturer, ROM_SAMSUNG)) {
            bean.name = ROM_SAMSUNG[0];
        } else if (isRightRom(brand, manufacturer, ROM_MEIZU)) {
            bean.name = ROM_MEIZU[0];
        } else if (isRightRom(brand, manufacturer, ROM_LENOVO)) {
            bean.name = ROM_LENOVO[0];
        } else if (isRightRom(brand, manufacturer, ROM_SMARTISAN)) {
            bean.name = ROM_SMARTISAN[0];
        } else if (isRightRom(brand, manufacturer, ROM_HTC)) {
            bean.name = ROM_HTC[0];
        } else if (isRightRom(brand, manufacturer, ROM_SONY)) {
            bean.name = ROM_SONY[0];
        } else if (isRightRom(brand, manufacturer, ROM_GIONEE)) {
            bean.name = ROM_GIONEE[0];
        } else if (isRightRom(brand, manufacturer, ROM_MOTOROLA)) {
            bean.name = ROM_MOTOROLA[0];
        } else {
            bean.name = manufacturer;
        }
        bean.version = getRomVersion("");
        return bean;
    }

    @Override
    public String getModel() {
        return Build.MODEL;
    }

    @Override
    public boolean isDoubleSim() {
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
            return false;
        }

        TelephonyManager telephonyManager = (TelephonyManager) ZljUtils.getApp().getSystemService(Context.TELEPHONY_SERVICE);
        int phoneCount = telephonyManager.getPhoneCount();
        return phoneCount >= 2;
    }

    private boolean isRightRom(final String brand, final String manufacturer, final String... names) {
        for (String name : names) {
            if (brand.contains(name) || manufacturer.contains(name)) {
                return true;
            }
        }
        return false;
    }

    private String getManufacturer() {
        try {
            String manufacturer = Build.MANUFACTURER;
            if (!TextUtils.isEmpty(manufacturer)) {
                return manufacturer.toLowerCase();
            }
        } catch (Throwable ignore) { /**/ }
        return UNKNOWN;
    }

    @Override
    public String getBrand() {
        try {
            String brand = Build.BRAND;
            if (!TextUtils.isEmpty(brand)) {
                return brand.toLowerCase();
            }
        } catch (Throwable ignore) { /**/ }
        return UNKNOWN;
    }

    private String getRomVersion(final String propertyName) {
        String ret = "";
        if (!TextUtils.isEmpty(propertyName)) {
            ret = getSystemProperty(propertyName);
        }
        if (TextUtils.isEmpty(ret) || ret.equals(UNKNOWN)) {
            try {
                String display = Build.DISPLAY;
                if (!TextUtils.isEmpty(display)) {
                    ret = display.toLowerCase();
                }
            } catch (Throwable ignore) { /**/ }
        }
        if (TextUtils.isEmpty(ret)) {
            return UNKNOWN;
        }
        return ret;
    }

    private String getSystemProperty(final String name) {
        String prop = getSystemPropertyByShell(name);
        if (!TextUtils.isEmpty(prop)) return prop;
        prop = getSystemPropertyByStream(name);
        if (!TextUtils.isEmpty(prop)) return prop;
        if (Build.VERSION.SDK_INT < 28) {
            return getSystemPropertyByReflect(name);
        }
        return prop;
    }

    @Override
    public String getSystemPropertyByShell(final String propName) {
        String line;
        BufferedReader input = null;
        try {
            Process p = Runtime.getRuntime().exec("getprop " + propName);
            input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
            String ret = input.readLine();
            if (ret != null) {
                return ret;
            }
        } catch (IOException ignore) {
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException ignore) { /**/ }
            }
        }
        return "";
    }

    private String getSystemPropertyByStream(final String key) {
        try {
            Properties prop = new Properties();
            FileInputStream is = new FileInputStream(
                    new File(Environment.getRootDirectory(), "build.prop")
            );
            prop.load(is);
            return prop.getProperty(key, "");
        } catch (Exception ignore) { /**/ }
        return "";
    }

    private String getSystemPropertyByReflect(String key) {
        try {
            @SuppressLint("PrivateApi")
            Class<?> clz = Class.forName("android.os.SystemProperties");
            Method getMethod = clz.getMethod("get", String.class, String.class);
            return (String) getMethod.invoke(clz, key, "");
        } catch (Exception e) { /**/ }
        return "";
    }

    public static class RomInfo {
        private String name;
        private String version;

        public String getName() {
            return name;
        }

        public String getVersion() {
            return version;
        }

        @Override
        public String toString() {
            return "RomInfo{name=" + name +
                    ", version=" + version + "}";
        }
    }

    @Override
    public long getRomSize() {
        ActivityManager am = (ActivityManager) ZljUtils.getApp().getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        am.getMemoryInfo(mi);
        Log.d("totalMem", "totalMem-->" + mi.totalMem);
        return mi.totalMem;
    }

    @Override
    public String getRomSizeWithUnit() {
        ActivityManager am = (ActivityManager) ZljUtils.getApp().getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        am.getMemoryInfo(mi);
        Log.d("totalMem", "totalMem-->" + mi.totalMem);
        long totalBytes = mi.totalMem;
        String totalGB = "";
        if (totalBytes > 1024 * 1024L && totalBytes <= 256 * 1024 * 1024L) {
            totalGB = "256M";
        } else if (totalBytes > 1024 * 1024L && totalBytes <= 512 * 1024 * 1024L) {
            totalGB = "512M";
        } else if (totalBytes > 512 * 1024 * 1024L && totalBytes <= 1024 * 1024 * 1024L) {
            totalGB = "1G";
        } else if (totalBytes > 1024 * 1024 * 1024L && totalBytes <= 2 * 1024 * 1024 * 1024L) {
            totalGB = "2G";
        } else if (totalBytes > 2 * 1024 * 1024 * 1024L && totalBytes <= 3 * 1024 * 1024 * 1024L) {
            totalGB = "3G";
        } else if (totalBytes > 3 * 1024 * 1024 * 1024L && totalBytes <= 4 * 1024 * 1024 * 1024L) {
            totalGB = "4G";
        } else if (totalBytes > 4 * 1024 * 1024 * 1024L && totalBytes <= 6 * 1024 * 1024 * 1024L) {
            totalGB = "6G";
        } else if (totalBytes > 6 * 1024 * 1024 * 1024L && totalBytes <= 8 * 1024 * 1024 * 1024L) {
            totalGB = "8G";
        } else if (totalBytes > 8 * 1024 * 1024 * 1024L && totalBytes <= 10 * 1024 * 1024 * 1024L) {
            totalGB = "10G";
        } else if (totalBytes > 10 * 1024 * 1024 * 1024L && totalBytes <= 12 * 1024 * 1024 * 1024L) {
            totalGB = "12G";
        } else if (totalBytes > 12 * 1024 * 1024 * 1024L && totalBytes <= 16 * 1024 * 1024 * 1024L) {
            totalGB = "16G";
        } else if (totalBytes > 16 * 1024 * 1024 * 1024L && totalBytes <= 32 * 1024 * 1024 * 1024L) {
            totalGB = "32G";
        } else if (totalBytes > 32 * 1024 * 1024 * 1024L && totalBytes <= 64 * 1024 * 1024 * 1024L) {
            totalGB = "64G";
        } else if (totalBytes > 64 * 1024 * 1024 * 1024L && totalBytes <= 128 * 1024 * 1024 * 1024L) {
            totalGB = "128G";
        } else if (totalBytes > 128 * 1024 * 1024 * 1024L && totalBytes <= 256 * 1024 * 1024 * 1024L) {
            totalGB = "256G";
        } else if (totalBytes > 256 * 1024 * 1024 * 1024L && totalBytes <= 512 * 1024 * 1024 * 1024L) {
            totalGB = "512G";
        } else if (totalBytes > 512 * 1024 * 1024 * 1024L && totalBytes <= 1024 * 1024 * 1024 * 1024L) {
            totalGB = "1T";
        }
        return totalGB;// 将获取的内存大小规格化
    }

    @Override
    public String getSdCardTotalSizeWithUnit() {
        try {
            File path = Environment.getExternalStorageDirectory();
            StatFs stat = new StatFs(path.getAbsolutePath());
            long totalBytes = stat.getTotalBytes();

            String totalGB = "没有匹配到相应的SD卡";
            if (totalBytes > 1024 * 1024L && totalBytes <= 256 * 1024 * 1024L) {
                totalGB = "256M";
            } else if (totalBytes > 1024 * 1024L && totalBytes <= 512 * 1024 * 1024L) {
                totalGB = "512M";
            } else if (totalBytes > 512 * 1024 * 1024L && totalBytes <= 1024 * 1024 * 1024L) {
                totalGB = "1G";
            } else if (totalBytes > 1024 * 1024 * 1024L && totalBytes <= 2 * 1024 * 1024 * 1024L) {
                totalGB = "2G";
            } else if (totalBytes > 2 * 1024 * 1024 * 1024L && totalBytes <= 4 * 1024 * 1024 * 1024L) {
                totalGB = "4G";
            } else if (totalBytes > 4 * 1024 * 1024 * 1024L && totalBytes <= 8 * 1024 * 1024 * 1024L) {
                totalGB = "8G";
            } else if (totalBytes > 8 * 1024 * 1024 * 1024L && totalBytes <= 16 * 1024 * 1024 * 1024L) {
                totalGB = "16G";
            } else if (totalBytes > 16 * 1024 * 1024 * 1024L && totalBytes <= 32 * 1024 * 1024 * 1024L) {
                totalGB = "32G";
            } else if (totalBytes > 32 * 1024 * 1024 * 1024L && totalBytes <= 64 * 1024 * 1024 * 1024L) {
                totalGB = "64G";
            } else if (totalBytes > 64 * 1024 * 1024 * 1024L && totalBytes <= 128 * 1024 * 1024 * 1024L) {
                totalGB = "128G";
            } else if (totalBytes > 128 * 1024 * 1024 * 1024L && totalBytes <= 256 * 1024 * 1024 * 1024L) {
                totalGB = "256G";
            } else if (totalBytes > 256 * 1024 * 1024 * 1024L && totalBytes <= 512 * 1024 * 1024 * 1024L) {
                totalGB = "512G";
            } else if (totalBytes > 512 * 1024 * 1024 * 1024L && totalBytes <= 1024 * 1024 * 1024 * 1024L) {
                totalGB = "1T";
            }
            return totalGB;
        } catch (Exception e) {
            ZljUtils.LOG().d("getSdCardTotalSizeWithUnit", e.getMessage());
            e.printStackTrace();
        }

        return "";
    }

    @Override
    public String getSystemCode() {
        return Build.VERSION.RELEASE;
    }

    @Override
    public String getAppVersionCode() {
        int verCode = -1;
        try {
            String packageName = ZljUtils.getApp().getPackageName();
            verCode = ZljUtils.getApp().getPackageManager()
                    .getPackageInfo(packageName, 0).versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return String.valueOf(verCode);
    }

    @Override
    public String getAppVersionName() {
        String versionName = "";
        try {
            String packageName = ZljUtils.getApp().getPackageName();
            versionName = ZljUtils.getApp().getPackageManager()
                    .getPackageInfo(packageName, 0).versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionName;
    }

    @SuppressLint("MissingPermission")
    @Override
    public String getImei() {
        if (ImeiBlackList.isInBlackList(getModel())) {
            return null;
        }

        try {
//            TelephonyManager tm = (TelephonyManager) ZljUtils.getApp().getSystemService(Context.TELEPHONY_SERVICE);
//            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//                try {
//                    Class clazz = tm.getClass();
//                    //noinspection unchecked
//                    Method getImeiMethod = clazz.getDeclaredMethod("getImei");
//                    getImeiMethod.setAccessible(true);
//                    String imei = (String) getImeiMethod.invoke(tm);
//
//                    if (imei != null && imei.length() == 15) {
//                        return imei;
//                    }
//
//                    @SuppressLint("MissingPermission")
//                    String imei_1 = getIMEI_1();
//
//                    if (imei_1 != null && imei_1.length() == 15) {
//                        return imei_1;
//                    }
//
//                } catch (Exception e) {
//                    Log.e("PhoneUtils", "getIMEI: ", e);
//                }
//            }

            return getImeiByReflection(ZljUtils.getApp());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String getSerialNo() {
        String serialNumber;

        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class);

            serialNumber = (String) get.invoke(c, "gsm.sn1");
            if (serialNumber.equals(""))
                serialNumber = (String) get.invoke(c, "ril.serialnumber");
            if (serialNumber.equals(""))
                serialNumber = (String) get.invoke(c, "ro.serialno");
            if (serialNumber.equals(""))
                serialNumber = (String) get.invoke(c, "sys.serialnumber");
            if (serialNumber.equals(""))
                serialNumber = Build.SERIAL;

            if (isEmptyOrUnknown(serialNumber)) {
                serialNumber = getSystemPropertyByShell("ro.serialno");
            }
            if (isEmptyOrUnknown(serialNumber)) {
                serialNumber = getSystemPropertyByShell("ro.boot.serialno");
            }
            /**
             * 魅族16s pro通过这种方式才能获取
             */
            if (isEmptyOrUnknown(serialNumber)) {
                serialNumber = getSystemPropertyByShell("ro.meizu.serialno");
            }
            // If none of the methods above worked
            if (serialNumber.equals(""))
                serialNumber = null;
        } catch (Exception e) {
            e.printStackTrace();
            serialNumber = Build.SERIAL;
        }

        if (serialNumber != null && serialNumber.toLowerCase().contains("unknown")) {
            serialNumber = null;
        }


        return serialNumber;
    }

    /**
     * 是否empty 或者包含unknown
     *
     * @param text
     * @return
     */
    private boolean isEmptyOrUnknown(String text) {
        return TextUtils.isEmpty(text) || text.toLowerCase().contains("unknown");
    }


    @Override
    public String getCPUCodeName() {
        return Build.HARDWARE;
    }

    @Nullable
    @Override
    public String getMarketName() {
        if (mModelMap.size() == 0) {
            initTinyModel();
        }

        String model = getModel();
        String key = mModelMap.get(model);
        if (key == null) {
            if (ZljUtils.ROM().isHuawei() || ZljUtils.ROM().isHonor()) {
                key = "ro.config.marketing_name";
            } else if (ZljUtils.ROM().isOppo() || ZljUtils.ROM().isRealMe()) {
                key = "ro.oppo.market.name";
            } else if (ZljUtils.ROM().isVivo()) {
                key = "ro.vivo.market.name";
            } else if (ZljUtils.ROM().isSamsung()) {
                key = "ro.product.name";
            } else if (ZljUtils.ROM().isNubia()) {
                key = "persist.sys.devicename";
            } else if (ZljUtils.ROM().isXiaomi()) {
                key = "ro.product.marketname";
            }
        }

        if (key == null) {
            return null;
        }

        String marketName = getSystemPropertyByShell(key);
        if (TextUtils.equals("PD1728UD_FULL_SC", marketName)) {
            return "vivo x21全面屏";
        }

        if (TextUtils.equals("PD1728UD_CT-FIFA", marketName)) {
            return "vivo x21 FIFA世界杯非凡版";
        }

        return marketName;
    }

    @Nullable
    @Override
    public String getHuaweiEmuiVersion() {
        return getSystemPropertyByShell("ro.huawei.build.display.id");
    }

    /**
     * IMEI 1号
     *
     * @return
     */
    @SuppressLint("MissingPermission")
    @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
    private String getIMEI_1() {
        TelephonyManager tm = (TelephonyManager) ZljUtils.getApp().getSystemService(Context.TELEPHONY_SERVICE);
        if (ActivityCompat.checkSelfPermission(ZljUtils.getApp(), Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            return null;
        }

        return tm != null ? tm.getDeviceId() : null;
    }

    /**
     * Return the IMEI.
     * <p>Must hold {@code <uses-permission android:name="android.permission.READ_PHONE_STATE" />}</p>
     *
     * @return the IMEI
     */
    @SuppressLint({"HardwareIds", "MissingPermission"})
    @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
    public String getImeiByReflection(@NonNull Context context) {
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return tm.getImei();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            try {
                Class<?> clazz = tm.getClass();
                Method getImeiMethod = clazz.getDeclaredMethod("getImei", int.class);
                getImeiMethod.setAccessible(true);
                String imei = (String) getImeiMethod.invoke(tm, 0);
                if (imei != null && imei.length() == 15) {
                    return imei;
                }
            } catch (Exception e) {
                Log.e("PhoneUtils", "getIMEI: ", e);
            }
        }
        String imei = tm.getDeviceId();
        if (imei != null && imei.length() == 15) {
            return imei;
        }
        return "";
    }

    public static class VivoLiftCameraModelList {
        public static final List<String> mModelList = new ArrayList<>();

        static {
            mModelList.add("v1832t");
            mModelList.add("v1832a");
            mModelList.add("v1831t");
            mModelList.add("v1831a");
            mModelList.add("v1829a");
            mModelList.add("v1829t");
            mModelList.add("v1836a");
            mModelList.add("v1838t");
            mModelList.add("v1838a");
            mModelList.add("vivo nex a");
            mModelList.add("vivo nex s");
            mModelList.add("v1821t");
            mModelList.add("v1821a");
            mModelList.add("v1924a");
            mModelList.add("v1923a");
            mModelList.add("v1950a");
        }
    }
}
